<!DOCTYPE html>


<html lang="zh-CN">


<head>
  <meta charset="utf-8" />
    
  <meta name="description" content="迎着朝阳的博客" />
  
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
  <title>
    spring之高频面试题 |  迎着朝阳
  </title>
  <meta name="generator" content="hexo-theme-ayer">
  
  <link rel="shortcut icon" href="https://dxysun.com/static/yan.png" />
  
  
<link rel="stylesheet" href="/dist/main.css">

  
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/Shen-Yu/cdn/css/remixicon.min.css">

  
<link rel="stylesheet" href="/css/custom.css">

  
  
<script src="https://cdn.jsdelivr.net/npm/pace-js@1.0.2/pace.min.js"></script>

  
  

  
<script>
var _hmt = _hmt || [];
(function() {
	var hm = document.createElement("script");
	hm.src = "https://hm.baidu.com/hm.js?aa994a8d65700b8835787dd39d079d7e";
	var s = document.getElementsByTagName("script")[0]; 
	s.parentNode.insertBefore(hm, s);
})();
</script>


</head>

</html>

<body>
  <div id="app">
    
      
    <main class="content on">
      <section class="outer">
  <article
  id="post-springForInterview"
  class="article article-type-post"
  itemscope
  itemprop="blogPost"
  data-scroll-reveal
>
  <div class="article-inner">
    
    <header class="article-header">
       
<h1 class="article-title sea-center" style="border-left:0" itemprop="name">
  spring之高频面试题
</h1>
 

    </header>
     
    <div class="article-meta">
      <a href="/2021/09/05/springForInterview/" class="article-date">
  <time datetime="2021-09-05T01:48:45.000Z" itemprop="datePublished">2021-09-05</time>
</a> 
  <div class="article-category">
    <a class="article-category-link" href="/categories/spring/">spring</a>
  </div>
  
<div class="word_count">
    <span class="post-time">
        <span class="post-meta-item-icon">
            <i class="ri-quill-pen-line"></i>
            <span class="post-meta-item-text"> 字数统计:</span>
            <span class="post-count">5.7k</span>
        </span>
    </span>

    <span class="post-time">
        &nbsp; | &nbsp;
        <span class="post-meta-item-icon">
            <i class="ri-book-open-line"></i>
            <span class="post-meta-item-text"> 阅读时长≈</span>
            <span class="post-count">21 分钟</span>
        </span>
    </span>
</div>
 
    </div>
      
    <div class="tocbot"></div>




  
    <div class="article-entry" itemprop="articleBody">
       
  <p>spring之高频面试题</p>
<a id="more"></a>

<h2 id="1、什么是Spring框架？Spring框架有哪些主要模块？"><a href="#1、什么是Spring框架？Spring框架有哪些主要模块？" class="headerlink" title="1、什么是Spring框架？Spring框架有哪些主要模块？"></a>1、什么是Spring框架？Spring框架有哪些主要模块？</h2><p>Spring框架是一个为Java应用程序的开发提供了综合、广泛的基础性支持的Java平台。Spring帮助开发者解决了开发中基础性的问题，使得开发人员可以专注于应用程序的开发。Spring框架本身亦是按照设计模式精心打造，这使得我们可以在开发环境中安心的集成Spring框架，不必担心Spring是如何在后台进行工作的。</p>
<p>Spring框架至今已集成了20多个模块。这些模块主要被分如下图所示的核心容器、数据访问/集成、 Web、AOP（面向切面编程）、工具、消息和测试模块。</p>
<p><img src="https://tu.dxysun.com/image-20210905095324453-20210905095325.png" alt="image-20210905095324453"></p>
<h2 id="2、使用Spring框架能带来哪些好处？"><a href="#2、使用Spring框架能带来哪些好处？" class="headerlink" title="2、使用Spring框架能带来哪些好处？"></a>2、使用Spring框架能带来哪些好处？</h2><p>下面列举了一些使用Spring框架带来的主要好处：</p>
<p>1、 Dependency Injection（Dl）方法使得构造器和JavaBean properties文件中的依赖关系一目了然。</p>
<p>2、与EJB容器相比较，IOC容器更加趋向于轻量级。这样一来IOC容器在有限的内存和CPU资源的情况下进行应用程序的开发和发布就变得十分有利。</p>
<p>3、Spring并没有闭门造车，Spring利用了已有的技术比如ORM框架、logging框架、J2EE、Quartz 和JDKTimer，以及其他视图技术。</p>
<p>4、Spring框架是按照模块的形式来组织的。由包和类的编号就可以看出其所属的模块，开发者仅仅需要选用他们需要的模块即可。</p>
<p>5、要测试一项用Spring开发的应用程序十分简单，因为测试相关的环境代码都已经囊括在框架中了。 更加简单的是，利用JavaBean形式的POJO类，可以很方便的利用依赖注入来写入测试数据。</p>
<p>5、Spring的Web框架亦是一个精心设计的WebMVC框架，为开发者们在web框架的选择上提供了一个除了主流框架比如Struts、过度设计的、不流行web框架的以外的有力选项。</p>
<p>6、Spring提供了一个便捷的事务管理接口，适用于小型的本地事务处理（比如在单DB的环境下）和复杂的共同事务处理（比如利用JTA的复杂DB环境）。</p>
<h2 id="3、什么是控制反转（IOC）？什么是依赖注入？"><a href="#3、什么是控制反转（IOC）？什么是依赖注入？" class="headerlink" title="3、什么是控制反转（IOC）？什么是依赖注入？"></a>3、什么是控制反转（IOC）？什么是依赖注入？</h2><p>1、控制反转是应用于软件工程领域中的，在运行时被装配器对象来绑定耦合对象的一种编程技巧，对象之间耦合关系在编译时通常是未知的。在传统的编程方式中，业务逻辑的流程是由应用程序中的早已被设定好关联关系的对象来决定的。在使用控制反转的情况下，业务逻辑的流程是由对象关系图来决定的，该对象关系图由装配器负责实例化，这种实现方式还可以将对象之间的关联关系的定义抽象化。而绑定的过程是通过“依赖注入”实现的。</p>
<p>2、控制反转是一种以给予应用程序中目标组件更多控制为目的设计范式，并在我们的实际工作中起到了有效的作用。</p>
<p>3、依赖注入是在编译阶段尚未知所需的功能是来自哪个的类的情况下，将其他对象所依赖的功能对象实例化的模式。这就需要一种机制用来激活相应的组件以提供特定的功能，所以依赖注入是控制反转的基础。</p>
<h2 id="4、在Java中依赖注入有哪些方式？"><a href="#4、在Java中依赖注入有哪些方式？" class="headerlink" title="4、在Java中依赖注入有哪些方式？"></a>4、在Java中依赖注入有哪些方式？</h2><p>1.构造器注入</p>
<p>2.Setter方法注入</p>
<p>3.接口注入，直接属性注入</p>
<h2 id="5、BeanFactory和ApplicationContext有什么区别？"><a href="#5、BeanFactory和ApplicationContext有什么区别？" class="headerlink" title="5、BeanFactory和ApplicationContext有什么区别？"></a>5、BeanFactory和ApplicationContext有什么区别？</h2><p>BeanFactory可以理解为含有bean集合的工厂类。BeanFactory包含了种bean的定义，以便在接收到客户端请求时将对应的bean实例化。</p>
<p>BeanFactory还能在实例化对象的时生成协作类之间的关系。此举将bean自身与bean客户端的配置中解放出来。BeanFactory还包含了bean生命周期的控制，调用客户端的初始化方法（initializationMethods）和销毁方法（destruction Methods）。</p>
<p>从表面上看，ApplicationContext如同bean factory一样具有bean定义、bean关联关系的设置，根据请求分发bean的功能。但ApplicationContext在此基础上还提供了其他的功能。</p>
<p>1.提供了支持国际化的文本消息</p>
<p>2.统一的资源文件读取方式</p>
<p>3.已在监听器中注册的bean的事件</p>
<p>以下是三种较常见的ApplicationContext实现方式：</p>
<p>1、ClassPathXmlApplicationContext：从classpath的XML配置文件中读取上下文，并生成上下文定义。应用程序上下文从程序环境变量中取得<br> <code>ApplicationContext context = new ClassPathXmlApplicationContext( &quot;application.xml&quot;);</code></p>
<p> 2、 FileSystemXmlApplicationContext ：由文件系统中的XML配置文件读取上下文。</p>
<p><code>ApplicationContext context = new FileSystemXmlApplicationContext( “application.xml&quot;);</code></p>
<p>3、XmlWebApplicationContext：由Web应用的XML文件读取上下文。</p>
<h2 id="6、Spring提供几种配置方式来设置元数据？"><a href="#6、Spring提供几种配置方式来设置元数据？" class="headerlink" title="6、Spring提供几种配置方式来设置元数据？"></a>6、Spring提供几种配置方式来设置元数据？</h2><p>将Spring配置到应用开发中有以下三种方式：</p>
<p>1.基于XML的配置</p>
<p>2.基于注解的配置</p>
<p>3.基于Java的配置</p>
<h2 id="7、如何使用XML配置的方式配置Spring？"><a href="#7、如何使用XML配置的方式配置Spring？" class="headerlink" title="7、如何使用XML配置的方式配置Spring？"></a>7、如何使用XML配置的方式配置Spring？</h2><p>在Spring框架中，依赖和服务需要在专门的配置文件来实现，我常用的XML格式的配置文件。这些配置文件的格式通常用开头，然后一系列的bean定义和专门的应用配置选项组成。</p>
<p>SpringXML配置的主要目的时候是使所有的Spring组件都可以用xml文件的形式来进行配置。这意味着不会出现其他的Spring配置类型（比如声明的方式或基于Java Class的配置方式）。</p>
<p>Spring的XML配置方式是使用被Spring命名空间的所支持的一系列的XML标签来实现的。Spring 有以下主要的命名空间：context、beans、jdbc、tx、aop、mvc和aso。</p>
<h2 id="8、Spring提供哪些配置形式？"><a href="#8、Spring提供哪些配置形式？" class="headerlink" title="8、Spring提供哪些配置形式？"></a>8、Spring提供哪些配置形式？</h2><p>Spring对Java配置的支持是由@Configuration注解和@Bean注解来实现的。由@Bean注解的方法将会实例化、配置和初始化一个新对象，这个对象将由Spring的IOC容器来管理。@Bean声明所起到的作用与元素类似。被@Configuration所注解的类则表示这个类的主要目的是作为bean定义的资源。被@Confiquration声明的类可以通过在同一个类的内部调用@bean方法夹设置嵌入bean的依赖关系。</p>
<p>@Confiquration配置与xml的配置等效。</p>
<h2 id="9、怎样用注解的方式配置Spring？"><a href="#9、怎样用注解的方式配置Spring？" class="headerlink" title="9、怎样用注解的方式配置Spring？"></a>9、怎样用注解的方式配置Spring？</h2><p>Spring在2.5版本以后开始支持用注解的方式来配置依赖注入。可以用注解的方式来替代XML方式的bean描述，可以将bean描述转移到组件类的内部，只需要在相关类上、方法上或者字段声明上使用注解即可。</p>
<p>注解注入将会被容器在XML注入之前被处理，所以后者会覆盖掉前者对于同一个属性的处理结果。</p>
<p>注解装配在Spring中是默认关闭的。所以需要在Spring文件中配置一下才能使用基于注解的装配模式。如果你想要在你的应用程序中使用关于注解的方法的话，请参考如下的配置。</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">beans</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">context:annotation-config</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">beans</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>在标签配置完成以后，就可以用注解的方式在Spring中向属性、方法和构造方法中自动装配变量。</p>
<p>下面是几种比较重要的注解类型：</p>
<p>1.@Required：该注解应用于设值方法。</p>
<p>2.@Autowired：该注解应用于有值设值方法、非设值方法、构造方法和变量。</p>
<p>3.@Qualifier：该注解和@Autowired注解搭配使用，用于消除特定bean自动装配的歧义。</p>
<p>4.JSR-250 Annotations：Spring支持基于JSR-250注解的以下注解，@Resource、@PostConstruct 和@PreDestroy。</p>
<h2 id="10、请解释Spring-Bean的生命周期？"><a href="#10、请解释Spring-Bean的生命周期？" class="headerlink" title="10、请解释Spring Bean的生命周期？"></a>10、请解释Spring Bean的生命周期？</h2><p>Spring Bean的生命周期简单易懂。在一个bean实例被初始化时，需要执行一系列的初始化操作以达到可用的状态。同样的，当一个bean不在被调用时需要进行相关的析构操作，并从bean容器中移除。</p>
<p>Spring bean factory负责管理在spring容器中被创建的bean的生命周期。</p>
<p>Bean的生命周期由两组回调（call back）方法组成。</p>
<p>1.初始化之后调用的回调方法。</p>
<p>2.销毁之前调用的回调方法。</p>
<p>Spring框架提供了以下四种方式来管理bean的生命周期事件：</p>
<p>1、lnitializingBean和DisposableBean回调接口</p>
<p>2、针对特殊行为的其他Aware接口</p>
<p>3、Bean配置文件中的Custom init()方法和destroy()方法</p>
<p>4、@PostConstruct和@PreDestroy注解方式</p>
<h2 id="11、Spring-Bean作用域之间的区别？"><a href="#11、Spring-Bean作用域之间的区别？" class="headerlink" title="11、Spring Bean作用域之间的区别？"></a>11、Spring Bean作用域之间的区别？</h2><p>Spring容器中的bean可以分为5个范围。所有范围的名称都是自说明的，但是为了避免混淆，还是让我们来解释一下：</p>
<p>1.singleton：这种bean范围是默认的，这种范围确保不管接受到多少个请求，每个容器中只有一个bean的实例，单例的模式由bean factory自身来维护。</p>
<p>2.prototype：原形范围与单例范围相反，为每一个bean请求提供一个实例。</p>
<p>3.request：在请求bean范围内会每一个来自客户端的网络请求创建一个实例，在请求完成以后，bean会失效并被垃圾回收器回收。</p>
<p>4.Session：与请求范围类似，确保每个session中有一个bean的实例，在session过期后，bean会随之失效。</p>
<p>5.global-session ：global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时，它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话，那么这全局变量需要存储在global-session中。</p>
<p>全局作用域与Servlet中的session作用域效果相同。</p>
<h2 id="12、什么是Spring-inner-beans？"><a href="#12、什么是Spring-inner-beans？" class="headerlink" title="12、什么是Spring inner beans？"></a>12、什么是Spring inner beans？</h2><p>在Spring框架中，无论何时bean被使用时，当仅被调用了一个属性。一个明智的做法是将这个bean声明为内部bean。内部bean可以用setter注入“属性”和构造方法注入“构造参数”的方式来实现。比如在我们的应用程序中，一个Customer类引用了一个Person类我们的要做的是创建一个Person的实例，然后在Customer内部使用。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">public class Customer&#123;</span><br><span class="line">private Person person;</span><br><span class="line">&#125;</span><br><span class="line">public class Person&#123;</span><br><span class="line">private String name;</span><br><span class="line">private String address;</span><br><span class="line">private int age;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<p>内部bean的声明方式如下：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"CustomerBean"</span> <span class="attr">class</span>=<span class="string">"com.common.Customer"</span>&gt;</span> </span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"person"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">"com.common.Person"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"name"</span> <span class="attr">value</span>=<span class="string">"lokesh"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"address"</span> <span class="attr">value</span>=<span class="string">"India"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"age"</span> <span class="attr">value</span>=<span class="string">"34"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>



<h2 id="13、Spring框架中的单例Beans是线程安全的么？"><a href="#13、Spring框架中的单例Beans是线程安全的么？" class="headerlink" title="13、Spring框架中的单例Beans是线程安全的么？"></a>13、Spring框架中的单例Beans是线程安全的么？</h2><p>Spring框架并没有对单例bean进行任何多线程的封装处理。关于单例bean的线程安全和并发问题需要开发者自行去搞定。</p>
<p>但实际上，大部分的Spring bean并没有可变的状态（比如Serview类和DAO类），所以在某种程度上说Spring的单例bean是线程安全的。</p>
<p>如果你的bean有多种状态的话（比如View Model对象），就需要自行保证线程安全。</p>
<p>最浅显的解决办法就是将多态bean的作用域由“singleton”变更为”prototype”。</p>
<h3 id="14、请举例说明如何在Spring中注入一个Java集合？"><a href="#14、请举例说明如何在Spring中注入一个Java集合？" class="headerlink" title="14、请举例说明如何在Spring中注入一个Java集合？"></a>14、请举例说明如何在Spring中注入一个Java集合？</h3><p> Spring提供了以下四种集合类的配置元素：</p>
<p>1、list  该标签用来装配可重复的list值。</p>
<p>2、set：该标签用来装配没有重复的set值。</p>
<p>3、map：该标签可用来注入键和值可以为任何类型的键值对品。</p>
<p>4、props：该标签支持注入键和值都是字符串类型的键值对。 </p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">beans</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"javaCollection"</span> <span class="attr">class</span>=<span class="string">"com.gupaoedu.JavaCollection"</span>&gt;</span> <span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"customlist"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">list</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>INDIA<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>Pakistan<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>USA<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>UK<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">list</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"customSet"</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;<span class="name">set</span>&gt;</span></span><br><span class="line">    <span class="tag">&lt;<span class="name">value</span>&gt;</span>INDIA<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>Pakistan<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>USA<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">value</span>&gt;</span>UK<span class="tag">&lt;/<span class="name">value</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">set</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"customMap"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">map</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">"1"</span> <span class="attr">value</span>=<span class="string">"INDIA"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">"2"</span> <span class="attr">value</span>=<span class="string">"Pakistan"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">"3"</span> <span class="attr">value</span>=<span class="string">"USA"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">entry</span> <span class="attr">key</span>=<span class="string">"4"</span> <span class="attr">value</span>=<span class="string">"UK"</span>/&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">map</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"customProperies"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">props</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">prop</span> <span class="attr">key</span>=<span class="string">"admin"</span>&gt;</span>admin<span class="tag">&lt;/<span class="name">prop</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">prop</span> <span class="attr">key</span>=<span class="string">"support"</span>&gt;</span>support<span class="tag">&lt;/<span class="name">prop</span>&gt;</span> </span><br><span class="line">  <span class="tag">&lt;/<span class="name">props</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>



<h2 id="15、如何向Spring-Bean中注入java-util-Properties？"><a href="#15、如何向Spring-Bean中注入java-util-Properties？" class="headerlink" title="15、如何向Spring Bean中注入java.util.Properties？"></a>15、如何向Spring Bean中注入java.util.Properties？</h2><p>第一种方法是使用如下面代码所示的标签：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"adminUser"</span> <span class="attr">class</span>=<span class="string">"com.common.Customer"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">property</span> <span class="attr">name</span>=<span class="string">"emails"</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">props</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;<span class="name">prop</span> <span class="attr">key</span>=<span class="string">"support"</span>&gt;</span>support<span class="tag">&lt;/<span class="name">prop</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">props</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">property</span>&gt;</span></span><br><span class="line"><span class="tag">&lt;/<span class="name">bean</span>&gt;</span></span><br></pre></td></tr></table></figure>

<p>也可用<code>util:</code>命名空间来从properties文件中创建出一个propertiesbean，然后利用setter方法注入bean的引用。</p>
<h2 id="16、请解释Spring-Bean的自动装配？"><a href="#16、请解释Spring-Bean的自动装配？" class="headerlink" title="16、请解释Spring Bean的自动装配？"></a>16、请解释Spring Bean的自动装配？</h2><p>在Spring框架中，在配置文件中设定bean的依赖关系是一个很好的机制，Spring容器还可以自动装配合作关系bean之间的关联关系。这意味着Spring可以通过向Bean Factory中注入的方式自动搞定bean之间的依赖关系。自动装配可以设置在每个bean上，也可以设定在特定的bean上。</p>
<p>下面的XML配置文件表明了如何根据名称将一个bean设置为自动装配：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">id</span>=<span class="string">"employeeDAO"</span> <span class="attr">class</span>=<span class="string">"com.gupaoedu.EmployeeDAOImpl"</span> <span class="attr">autowire</span>=<span class="string">"byName"</span> /&gt;</span></span><br></pre></td></tr></table></figure>

<blockquote>
<p>autowire 可以设置为 byName 或者 byType</p>
</blockquote>
<p>除了bean配置文件中提供的自动装配模式，还可以使用@Autowired注解来自动装配指定的bean。</p>
<p>在使用@Autowired注解之前需要在按照如下的配置方式在Spring配置文件进行配置才可以使用。</p>
<p><code>&lt;context:annotation-config /&gt;</code></p>
<p>也可以通过在配置文件中配置AutowiredAnnotationBeanPostProcessor达到相同的效果。</p>
<p><code>&lt;bean class =&quot;org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor&quot;/&gt;</code></p>
<p>配置好以后就可以使用@Autowired来标注了。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">@Autowired</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">EmployeeDAOImpl</span> <span class="params">(EmployeeManager manager)</span></span>&#123;</span><br><span class="line"><span class="keyword">this</span>.manager = manager;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>



<h2 id="17、自动装配有哪些局限性？"><a href="#17、自动装配有哪些局限性？" class="headerlink" title="17、自动装配有哪些局限性？"></a>17、自动装配有哪些局限性？</h2><p>自动装配有如下局限性：</p>
<p>重写：仍然需要使用和<code>&lt;property&gt;</code>设置指明依赖，这意味着总要重写自动装配。</p>
<p>原生数据类型：不能自动装配简单的属性，如原生类型、字符串。</p>
<p>模糊特性：自动装配总是没有自定义装配精确，因此，如果可能尽量使用自定义装配。</p>
<h2 id="18、请解释各种自动装配模式的区别？"><a href="#18、请解释各种自动装配模式的区别？" class="headerlink" title="18、请解释各种自动装配模式的区别？"></a>18、请解释各种自动装配模式的区别？</h2><p>在Spring框架中共有5种自动装配。</p>
<p>1.no：这是Spring框架的默认设置，在该设置下自动装配是关闭的，开发者需要自行在bean定义中用标签明确的设置依赖关系。</p>
<p>2.byName：该选项可以根据bean名称设置依赖关系。当向一个bean中自动装配一个属性时，容器将根据bean的名称自动在在配置文件中查询一个匹配的bean。如果找到的话，就装配这个属性，如果没找到的话就报错。</p>
<p>3.byType：该选项可以根据bean类型设置依赖关系。当向一个bean中自动装配一个属性时，容器将根据bean的类型自动在在配置文件中查询一个匹配的bean。如果找到的话，就装配这个属性，如果没找到的话就报错。</p>
<p>4.constructor：造器的自动装配和byType模式类似，但是仅仅适用于与有构造器相同参数的bean 如果在容器中没有找到与构造器参数类型一致的bean，那么将会抛出异常。</p>
<p>5.autodetect：该模式自动探测使用构造器自动装配或者byType自动装配。首先，首先会尝试找合适的带参数的构造器，如果找到的话就是用构造器自动装配，如果在bean内部没有找到相应的构造器或者是无参构造器，容器就会自动选择byTpe的自动装配方式。</p>
<h2 id="19、请举例解释-Required-Annotation？"><a href="#19、请举例解释-Required-Annotation？" class="headerlink" title="19、请举例解释@Required Annotation？"></a>19、请举例解释@Required Annotation？</h2><p>在产品级别的应用中，I0C容器可能声明了数十万了bean，bean与bean之间有着复杂的依赖关系。</p>
<p>设值注解方法的短板之一就是验证所有的属性是否被注解是一项十分困难的操作。</p>
<p>可以通过在中设置”dependency-check”来解决这个问题。</p>
<p>在应用程序的生命周期中，你可能不大愿意花时间在验证所有bean的属性是否按照上下文文件正确配置。或者你宁可验证某个bean的特定属性是否被正确的设置。即使是用“dependency-check”属性也不能很好的解决这个问题，在这种情况下，你需要使用@Required注解。</p>
<p>需要用如下的方式使用来标明bean的设值方法</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">EmployeeFactoryBean</span> <span class="keyword">extends</span> <span class="title">AbstractFactoryBean</span>&lt;<span class="title">object</span>&gt;</span></span><br><span class="line"><span class="class"></span>&#123; </span><br><span class="line"><span class="keyword">private</span> String designation;</span><br><span class="line"><span class="function"><span class="keyword">public</span> String <span class="title">getDesignation</span><span class="params">()</span></span>&#123;</span><br><span class="line"><span class="keyword">return</span> designation;</span><br><span class="line">&#125;</span><br><span class="line"><span class="meta">@Required</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">setDesignation</span><span class="params">(String designation)</span></span>&#123;</span><br><span class="line"><span class="keyword">this</span>.designation = designation;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>RequiredAnnotationBeanPostProcessor是Spring中的后置处理用来验证被@Required注解的bean属性是否被正确的设置了。</p>
<p>在使用RequiredAnnotationBeanPostProcesso来验证bean属性之前，首先要在IOC容器中对其进行注册：</p>
<figure class="highlight xml"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="tag">&lt;<span class="name">bean</span> <span class="attr">class</span>=<span class="string">"org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostprocessor"</span> /&gt;</span></span><br></pre></td></tr></table></figure>

<p>但是如果没有属性被用@Required注解过的话后置处理器会抛出一个BeanlnitializationException 异常。</p>
<h2 id="21、构造方法注入和设值注入有什么区别？"><a href="#21、构造方法注入和设值注入有什么区别？" class="headerlink" title="21、构造方法注入和设值注入有什么区别？"></a>21、构造方法注入和设值注入有什么区别？</h2><p>请注意以下明显的区别</p>
<p>1.在设值注入方法支持大部分的依赖注入，如果我们仅需要注入int、string和long型的变量，我们不要用设值的方法注入。对于基本类型，如果我们没有注入的话，可以为基本类型设置默认值。在构造方法注入不支持大部分的依赖注入，因为在调用构造方法中必须传入正确的构造参数，否则的话为报错。</p>
<p>2.设值注入不会重写构造方法的值。如果我们对同一个变量同时使用了构造方法注入又使用了设置方法注入的话，那么构造方法将不能覆盖由设值方法注入的值。很明显，因为构造方法尽在对象被创建时调用。</p>
<p>3.在使用设值注入时有可能还不能保证某种依赖是否已经被注人，也就是说这时对象的统赖关系有可能是不完整的。而在另一种情况下，构造器注入则不允许生成依赖关系不完整的对象。</p>
<p>4.在构造注入时如果对象A和对象B互相依赖，在创建对象A时Spring会抛出 ObjectCurrentlyInCreationException异常，因为在B对象被创建之前A对象是不能被创建的，反之亦然。所以Spring用设值注入的方法解决了循环依赖的问题，因对象的设值方法是在对象被创建之前被调用的。</p>
<h2 id="22、Spring框架中有哪些不同类型的事件？"><a href="#22、Spring框架中有哪些不同类型的事件？" class="headerlink" title="22、Spring框架中有哪些不同类型的事件？"></a>22、Spring框架中有哪些不同类型的事件？</h2><p>Spring的ApplicationContext提供了支持事件和代码中监听器的功能。</p>
<p>我们可以创建bean用来监听在ApplicationContext中发布的事件。ApplicationEvent类和在ApplicationContext接口中处理的事件，如果一个bean实现了ApplicationListener接口，当一个ApplicationEvent被发布以后，bean会自动被通知。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">AllApplicationEventListener</span> <span class="keyword">implements</span> <span class="title">ApplicationListener</span>&lt;<span class="title">ApplicationEvent</span>&gt;</span>&#123; </span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onApplicationEvent</span><span class="params">(ApplicationEvent applicationEvent)</span> </span>&#123;</span><br><span class="line"><span class="comment">//process event</span></span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Spring提供了以下5中标准的事件：</p>
<p>1.上下文更新事件（ContextRefreshedEvent）：该事件会在ApplicationContext被初始化或者更新时发布。也可以在调用ConfigurableApplicationContext接口中的refresh() 方法时被触发。</p>
<p>2.上下文开始事件（ContextStartedEvent）：当容器调用ConfiqurableApplicationContext的Start() 方法开始/重新开始容器时触发该事件。</p>
<p>3.上下文停止事件（ ContextStoppedEvent）：当容器调用ConfigurableApplicationContext的Stop() 方法停止容器时触发该事件。</p>
<p>4.上下文关闭事件（ContextClosedEvent）：当ApplicationContext被关闭时触发该事件。容器被关闭时，其管理的所有单例Bean都被销毁。</p>
<p>5.请求处理事件（RequestHandledEvent）：在Web应用中，当一个http请求（request）结束触发该事件。</p>
<p>除了上面介绍的事件以外，还可以通过扩展ApplicationEvent类来开发自定义的事件。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CustomApplicationEvent</span> <span class="keyword">extends</span> <span class="title">ApplicationEvent</span> </span>&#123;</span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="title">CustomApplicationEvent</span> <span class="params">(Object source, <span class="keyword">final</span> String msg)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">  <span class="keyword">super</span>.(source);</span><br><span class="line">    System.out.println(<span class="string">"Created a Custom event"</span>);</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>为了监听这个事件，还需要创建一个监听器：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CustomEventListener</span> <span class="keyword">implements</span> <span class="title">Applicationlistener</span>&lt;<span class="title">CustomApplicationEvent</span>&gt;</span></span><br><span class="line"><span class="class"></span>&#123; </span><br><span class="line"><span class="meta">@Override</span></span><br><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">onApplicationEvent</span><span class="params">(CustomApplicationEvent applicationEvent)</span></span>&#123;</span><br><span class="line">&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>之后通过applicationContext接口的publishEvent()方法来发布自定义事件。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">CustomApplicationEvent customEvent = <span class="keyword">new</span> CustomApplicationEvent(applicationContext,<span class="string">"Test message”);</span></span><br><span class="line"><span class="string">applicationContext.publishEvent(customEvent);</span></span><br></pre></td></tr></table></figure>



<h2 id="23、FileSystemResource和ClassPathResource有何区别？"><a href="#23、FileSystemResource和ClassPathResource有何区别？" class="headerlink" title="23、FileSystemResource和ClassPathResource有何区别？"></a>23、FileSystemResource和ClassPathResource有何区别？</h2><p>在FileSystemResource中需要给出spring-config.xml文件在你项目中的相对路径或者绝对路径。</p>
<p>在ClassPathResource中spring会在ClassPath中自动搜寻配置文件，所以要把ClassPathResource文件放在ClassPath下。</p>
<p>如果将spring-config.xml保存在了src文件夹下的话，只需给出配置文件的名称即可，因为src文件夹是默认。</p>
<p>简而言之，ClassPathResource在环境变量中读取配置文件，FileSystemResource在配置文件中读取配置文件。</p>
<h2 id="24、-Spring框架中都用到了哪些设计模式？"><a href="#24、-Spring框架中都用到了哪些设计模式？" class="headerlink" title="24、 Spring框架中都用到了哪些设计模式？"></a>24、 Spring框架中都用到了哪些设计模式？</h2><p>Spring框架中使用到了大量的设计模式，下面列举了比较有代表性的：</p>
<p>1、代理模式：在AOP和remoting中被用的比较多，AOP思想的底层实现技术，Spring中采用JDKProxy和CgLib类库。</p>
<p>3、模板模式：用来解决代码重复的问题。</p>
<p>2、单例模式：在spring配置文件中定义的bean默认为单例模式。比如RestTemplate，JmsTemplate，JpaTemplate。</p>
<p>4、委派模式：Srping提供了DispatcherServlet来对请求进行分发。</p>
<p>5、工厂模式：BeanFactory用来创建对象的实例，贯穿于BeanFactory /ApplicationContext接口的核心理念。</p>
<h2 id="26、请解释下Spring框架中的IOC容器？"><a href="#26、请解释下Spring框架中的IOC容器？" class="headerlink" title="26、请解释下Spring框架中的IOC容器？"></a>26、请解释下Spring框架中的IOC容器？</h2><p>Spring 中的org.springframework.beans包和org.springframework.context包构成了Spring框架IOC容器的基础。</p>
<p>BeanFactory接口提供了一个先进的配置机制，使得任何类型的对象的配置成为可能。ApplicationContex接口对BeanFactory（是一个子接口）进行了扩展，在BeanFactory的基础上添加了其他功能，比如与Spring的AOP更容易集成，也提供了处理message resource的机制（用于国际化）、事件传播以及应用层的特别配置，比如针对Web应用的WebApplicationContext。</p>
<h2 id="27、在Spring中可以注入nul或空字符串吗？"><a href="#27、在Spring中可以注入nul或空字符串吗？" class="headerlink" title="27、在Spring中可以注入nul或空字符串吗？"></a>27、在Spring中可以注入nul或空字符串吗？</h2><p>完全可以。</p>
 
      <!-- reward -->
      
      <div id="reword-out">
        <div id="reward-btn">
          打赏
        </div>
      </div>
      
    </div>
    

    <!-- copyright -->
    
    <footer class="article-footer">
       
<div class="share-btn">
      <span class="share-sns share-outer">
        <i class="ri-share-forward-line"></i>
        分享
      </span>
      <div class="share-wrap">
        <i class="arrow"></i>
        <div class="share-icons">
          
          <a class="weibo share-sns" href="javascript:;" data-type="weibo">
            <i class="ri-weibo-fill"></i>
          </a>
          <a class="weixin share-sns wxFab" href="javascript:;" data-type="weixin">
            <i class="ri-wechat-fill"></i>
          </a>
          <a class="qq share-sns" href="javascript:;" data-type="qq">
            <i class="ri-qq-fill"></i>
          </a>
          <a class="douban share-sns" href="javascript:;" data-type="douban">
            <i class="ri-douban-line"></i>
          </a>
          <!-- <a class="qzone share-sns" href="javascript:;" data-type="qzone">
            <i class="icon icon-qzone"></i>
          </a> -->
          
          <a class="facebook share-sns" href="javascript:;" data-type="facebook">
            <i class="ri-facebook-circle-fill"></i>
          </a>
          <a class="twitter share-sns" href="javascript:;" data-type="twitter">
            <i class="ri-twitter-fill"></i>
          </a>
          <a class="google share-sns" href="javascript:;" data-type="google">
            <i class="ri-google-fill"></i>
          </a>
        </div>
      </div>
</div>

<div class="wx-share-modal">
    <a class="modal-close" href="javascript:;"><i class="ri-close-circle-line"></i></a>
    <p>扫一扫，分享到微信</p>
    <div class="wx-qrcode">
      <img src="//api.qrserver.com/v1/create-qr-code/?size=150x150&data=https://dxysun.com/2021/09/05/springForInterview/" alt="微信分享二维码">
    </div>
</div>

<div id="share-mask"></div>  
  <ul class="article-tag-list" itemprop="keywords"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/tags/spring/" rel="tag">spring</a></li></ul>

    </footer>
  </div>

   
  <nav class="article-nav">
    
      <a href="/2021/10/11/mysqlForGeneratedColumn/" class="article-nav-link">
        <strong class="article-nav-caption">上一篇</strong>
        <div class="article-nav-title">
          
            MySQL5.7新特性之Generated Column
          
        </div>
      </a>
    
    
      <a href="/2021/09/04/springForTransaction/" class="article-nav-link">
        <strong class="article-nav-caption">下一篇</strong>
        <div class="article-nav-title">spring核心之事务相关</div>
      </a>
    
  </nav>

  
   
  
</article>

</section>
      <footer class="footer">
  <div class="outer">
    <ul>
      <li>
        Copyrights &copy;
        2015-2024
        <i class="ri-heart-fill heart_icon"></i> dxysun
      </li>
    </ul>
    <ul>
      <li>
        
        
        
        由 <a href="https://hexo.io" target="_blank">Hexo</a> 强力驱动
        <span class="division">|</span>
        主题 - <a href="https://github.com/Shen-Yu/hexo-theme-ayer" target="_blank">Ayer</a>
        
      </li>
    </ul>
    <ul>
      <li>
        
        
        <span>
  <span><i class="ri-user-3-fill"></i>访问人数:<span id="busuanzi_value_site_uv"></span></s>
  <span class="division">|</span>
  <span><i class="ri-eye-fill"></i>浏览次数:<span id="busuanzi_value_page_pv"></span></span>
</span>
        
      </li>
    </ul>
    <ul>
      
        <li>
          <a href="https://beian.miit.gov.cn" target="_black" rel="nofollow">豫ICP备17012675号-1</a>
        </li>
        
    </ul>
    <ul>
      
    </ul>
    <ul>
      <li>
        <!-- cnzz统计 -->
        
      </li>
    </ul>
  </div>
</footer>
      <div class="float_btns">
        <div class="totop" id="totop">
  <i class="ri-arrow-up-line"></i>
</div>

<div class="todark" id="todark">
  <i class="ri-moon-line"></i>
</div>

      </div>
    </main>
    <aside class="sidebar on">
      <button class="navbar-toggle"></button>
<nav class="navbar">
  
  <div class="logo">
    <a href="/"><img src="https://dxysun.com/static/logo.png" alt="迎着朝阳"></a>
  </div>
  
  <ul class="nav nav-main">
    
    <li class="nav-item">
      <a class="nav-item-link" href="/">主页</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/archives">归档</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/categories">分类</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/tags">标签</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/photos">相册</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/friends">友链</a>
    </li>
    
    <li class="nav-item">
      <a class="nav-item-link" href="/about">关于我</a>
    </li>
    
  </ul>
</nav>
<nav class="navbar navbar-bottom">
  <ul class="nav">
    <li class="nav-item">
      
      <a class="nav-item-link nav-item-search"  title="搜索">
        <i class="ri-search-line"></i>
      </a>
      
      
      <a class="nav-item-link" target="_blank" href="/atom.xml" title="RSS Feed">
        <i class="ri-rss-line"></i>
      </a>
      
    </li>
  </ul>
</nav>
<div class="search-form-wrap">
  <div class="local-search local-search-plugin">
  <input type="search" id="local-search-input" class="local-search-input" placeholder="Search...">
  <div id="local-search-result" class="local-search-result"></div>
</div>
</div>
    </aside>
    <script>
      if (window.matchMedia("(max-width: 768px)").matches) {
        document.querySelector('.content').classList.remove('on');
        document.querySelector('.sidebar').classList.remove('on');
      }
    </script>
    <div id="mask"></div>

<!-- #reward -->
<div id="reward">
  <span class="close"><i class="ri-close-line"></i></span>
  <p class="reward-p"><i class="ri-cup-line"></i>请我喝杯咖啡吧~</p>
  <div class="reward-box">
    
    <div class="reward-item">
      <img class="reward-img" src="https://tu.dxysun.com/alipay-20201219151322.jpg">
      <span class="reward-type">支付宝</span>
    </div>
    
    
    <div class="reward-item">
      <img class="reward-img" src="https://tu.dxysun.com/weixin-20201219151346.png">
      <span class="reward-type">微信</span>
    </div>
    
  </div>
</div>
    
<script src="/js/jquery-2.0.3.min.js"></script>


<script src="/js/lazyload.min.js"></script>

<!-- Tocbot -->


<script src="/js/tocbot.min.js"></script>

<script>
  tocbot.init({
    tocSelector: '.tocbot',
    contentSelector: '.article-entry',
    headingSelector: 'h1, h2, h3, h4, h5, h6',
    hasInnerContainers: true,
    scrollSmooth: true,
    scrollContainer: 'main',
    positionFixedSelector: '.tocbot',
    positionFixedClass: 'is-position-fixed',
    fixedSidebarOffset: 'auto'
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/jquery-modal@0.9.2/jquery.modal.min.css">
<script src="https://cdn.jsdelivr.net/npm/justifiedGallery@3.7.0/dist/js/jquery.justifiedGallery.min.js"></script>

<script src="/dist/main.js"></script>

<!-- ImageViewer -->

<!-- Root element of PhotoSwipe. Must have class pswp. -->
<div class="pswp" tabindex="-1" role="dialog" aria-hidden="true">

    <!-- Background of PhotoSwipe. 
         It's a separate element as animating opacity is faster than rgba(). -->
    <div class="pswp__bg"></div>

    <!-- Slides wrapper with overflow:hidden. -->
    <div class="pswp__scroll-wrap">

        <!-- Container that holds slides. 
            PhotoSwipe keeps only 3 of them in the DOM to save memory.
            Don't modify these 3 pswp__item elements, data is added later on. -->
        <div class="pswp__container">
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
            <div class="pswp__item"></div>
        </div>

        <!-- Default (PhotoSwipeUI_Default) interface on top of sliding area. Can be changed. -->
        <div class="pswp__ui pswp__ui--hidden">

            <div class="pswp__top-bar">

                <!--  Controls are self-explanatory. Order can be changed. -->

                <div class="pswp__counter"></div>

                <button class="pswp__button pswp__button--close" title="Close (Esc)"></button>

                <button class="pswp__button pswp__button--share" style="display:none" title="Share"></button>

                <button class="pswp__button pswp__button--fs" title="Toggle fullscreen"></button>

                <button class="pswp__button pswp__button--zoom" title="Zoom in/out"></button>

                <!-- Preloader demo http://codepen.io/dimsemenov/pen/yyBWoR -->
                <!-- element will get class pswp__preloader--active when preloader is running -->
                <div class="pswp__preloader">
                    <div class="pswp__preloader__icn">
                        <div class="pswp__preloader__cut">
                            <div class="pswp__preloader__donut"></div>
                        </div>
                    </div>
                </div>
            </div>

            <div class="pswp__share-modal pswp__share-modal--hidden pswp__single-tap">
                <div class="pswp__share-tooltip"></div>
            </div>

            <button class="pswp__button pswp__button--arrow--left" title="Previous (arrow left)">
            </button>

            <button class="pswp__button pswp__button--arrow--right" title="Next (arrow right)">
            </button>

            <div class="pswp__caption">
                <div class="pswp__caption__center"></div>
            </div>

        </div>

    </div>

</div>

<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/default-skin/default-skin.min.css">
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/photoswipe@4.1.3/dist/photoswipe-ui-default.min.js"></script>

<script>
    function viewer_init() {
        let pswpElement = document.querySelectorAll('.pswp')[0];
        let $imgArr = document.querySelectorAll(('.article-entry img:not(.reward-img)'))

        $imgArr.forEach(($em, i) => {
            $em.onclick = () => {
                // slider展开状态
                // todo: 这样不好，后面改成状态
                if (document.querySelector('.left-col.show')) return
                let items = []
                $imgArr.forEach(($em2, i2) => {
                    let img = $em2.getAttribute('data-idx', i2)
                    let src = $em2.getAttribute('data-target') || $em2.getAttribute('src')
                    let title = $em2.getAttribute('alt')
                    // 获得原图尺寸
                    const image = new Image()
                    image.src = src
                    items.push({
                        src: src,
                        w: image.width || $em2.width,
                        h: image.height || $em2.height,
                        title: title
                    })
                })
                var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, {
                    index: parseInt(i)
                });
                gallery.init()
            }
        })
    }
    viewer_init()
</script>

<!-- MathJax -->

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
      tex2jax: {
          inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
          processEscapes: true,
          skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
      }
  });

  MathJax.Hub.Queue(function() {
      var all = MathJax.Hub.getAllJax(), i;
      for(i=0; i < all.length; i += 1) {
          all[i].SourceElement().parentNode.className += ' has-jax';
      }
  });
</script>

<script src="https://cdn.jsdelivr.net/npm/mathjax@2.7.6/unpacked/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script>
  var ayerConfig = {
    mathjax: true
  }
</script>

<!-- Katex -->

<!-- busuanzi  -->


<script src="/js/busuanzi-2.3.pure.min.js"></script>


<!-- ClickLove -->

<!-- ClickBoom1 -->

<!-- ClickBoom2 -->

<!-- CodeCopy -->


<link rel="stylesheet" href="/css/clipboard.css">

<script src="https://cdn.jsdelivr.net/npm/clipboard@2/dist/clipboard.min.js"></script>
<script>
  function wait(callback, seconds) {
    var timelag = null;
    timelag = window.setTimeout(callback, seconds);
  }
  !function (e, t, a) {
    var initCopyCode = function(){
      var copyHtml = '';
      copyHtml += '<button class="btn-copy" data-clipboard-snippet="">';
      copyHtml += '<i class="ri-file-copy-2-line"></i><span>COPY</span>';
      copyHtml += '</button>';
      $(".highlight .code pre").before(copyHtml);
      $(".article pre code").before(copyHtml);
      var clipboard = new ClipboardJS('.btn-copy', {
        target: function(trigger) {
          return trigger.nextElementSibling;
        }
      });
      clipboard.on('success', function(e) {
        let $btn = $(e.trigger);
        $btn.addClass('copied');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-checkbox-circle-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPIED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-checkbox-circle-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
      clipboard.on('error', function(e) {
        e.clearSelection();
        let $btn = $(e.trigger);
        $btn.addClass('copy-failed');
        let $icon = $($btn.find('i'));
        $icon.removeClass('ri-file-copy-2-line');
        $icon.addClass('ri-time-line');
        let $span = $($btn.find('span'));
        $span[0].innerText = 'COPY FAILED';
        
        wait(function () { // 等待两秒钟后恢复
          $icon.removeClass('ri-time-line');
          $icon.addClass('ri-file-copy-2-line');
          $span[0].innerText = 'COPY';
        }, 2000);
      });
    }
    initCopyCode();
  }(window, document);
</script>


<!-- CanvasBackground -->


<script src="/js/dz.js"></script>



    
  </div>
</body>

</html>